package com.mediatecture.flex.component.UValueCalculator
{
	import Model.Construction;
	import Model.ConstructionLang;
	import Model.Layer;
	import Model.Material;
	
	import mx.collections.ArrayCollection;

	public class UValueCalculator
	{
		public static function calculateUValue(construction:ConstructionLang):Number
		{
			if(constructionIsHomogen(construction))
			{
				return calculateHomogenConstructionUvalue(construction);
			}
			else
			{
				return calculateNotHomogenConstructionUvalue(construction);
			}
		}
		
		private static function calculateHomogenConstructionUvalue(construction:ConstructionLang):Number
		{
			var result:Number = 0;
			
			var homogen:Number = calculateHomogenLayers(construction.layers) + 0.13 + 0.13;
			
			return 1/homogen;
		}
		
		private static function calculateNotHomogenConstructionUvalue(construction:ConstructionLang):Number
		{
			var result:Number = 0;
			
			var RtPrim:Number = calculateRtPrim(construction);
			var RtSecont:Number = calculateRtSecont(construction);
			
			result = 1/((RtPrim + RtSecont)/2);
			
			return result;
		}

		private static function calculateRtPrim(construction:ConstructionLang):Number
		{
			var result:Number = 0;
			
			var homogenLayersResult:Number = calculateHomogenLayers(construction.layers);
			var totalWidth:Number = getTotalWidthOfTheMaterialsInNonHomogenLayers(construction);
			var allMaterialTypes:ArrayCollection = getAllTypesOfMaterialsInNonHomogenLayers(construction);
			
			for(var i:Number = 0; i < allMaterialTypes.length; i++)
			{ 
				var materialRatio:Number = (getTotalWidthOfMaterialInNothomogenLayers(allMaterialTypes[i], construction.layers)/totalWidth);
				var Rmaterial:Number = (calculateNotHomogenLayerPerMaterial(allMaterialTypes[i], construction.layers) + homogenLayersResult + (2*0.13));
				result += materialRatio / Rmaterial;
			}
			
			return 1/result;
		}
		
		private static function calculateRtSecont(construction:ConstructionLang):Number
		{
			var result:Number = 0;
			var totalWidth:Number = getTotalWidthOfTheMaterialsInNonHomogenLayers(construction);
			var allMaterialTypes:ArrayCollection = getAllTypesOfMaterialsInNonHomogenLayers(construction);
			
			var thickness:Number = 0;
			var lambda:Number = 0;
			var ratio:Number = 0;
			
			for(var i:Number = 0; i < allMaterialTypes.length; i++)
			{ 
				for each(var layer:Layer in construction.layers)
				{
					if(!layer.homogen)
					{
						if(layerContainsTypeOfMaterial(allMaterialTypes[i],layer))
						{
							ratio = getTotalWidthOfMaterialInNothomogenLayers(allMaterialTypes[i],construction.layers) / totalWidth;
							lambda = getMaterialByType(allMaterialTypes[i],layer).lambda;
							thickness += layer.selectedDimention/100;
						}
					}
				}
				
				result += ratio / (thickness / lambda);
			}
			
			return (1/result) + calculateHomogenLayers(construction.layers);
		}
		
		private static function getTotalWidthOfTheMaterialsInNonHomogenLayers(construction:ConstructionLang):Number
		{
			var result:Number = 0;
			
			for each(var layer:Layer in construction.layers)
			{
				if(!layer.homogen)
				{
					for each(var material:Material in layer.materials)
					{
						result+= material.width/100;
					}
				}
			}
			
			return result;
		}
		
		private static function getAllTypesOfMaterialsInNonHomogenLayers(construction:ConstructionLang):ArrayCollection
		{
			var result:ArrayCollection = new ArrayCollection();
			
			for each(var layer:Layer in construction.layers)
			{
				if(!layer.homogen)
				{
					for each(var material:Material in layer.materials)
					{
						if(!result.contains(material.type))
						{	
							result.addItem(material.type);
						}
					}
				}
			}
			
			return result;
		}
		
		
		private static function calculateNotHomogenLayerPerMaterial(typeOfMaterial:Number, layers:ArrayCollection):Number
		{
			var result:Number = 0;
			
			for each( var layer:Layer in layers )
			{
				if(!layer.homogen && layerContainsTypeOfMaterial(typeOfMaterial,layer))
				{

					result += (layer.selectedDimention/100) / getMaterialByType(typeOfMaterial,layer).lambda;

				}
			}
			
			return result;
		}
		
		private static function calculateHomogenLayers(layers:ArrayCollection):Number
		{
			var result:Number = 0;
			
			for each( var layer:Layer in layers)
			{
				if(layer.homogen)
				{
					if(layer.thermalEffect)
					{
						result += (layer.selectedDimention/100) / (layer.materials[0] as Material).lambda;
					}
				}
			}
			
			return result;
		}
		
		private static function getTotalWidthOfMaterialInNothomogenLayers(typeOfMaterial:Number, layers:ArrayCollection):Number
		{
			var result:Number = 0;
			
			for each(var layer:Layer in layers)
			{
				if(!layer.homogen && layerContainsTypeOfMaterial(typeOfMaterial,layer))
				{
					result += getMaterialByType(typeOfMaterial,layer).width/100;
				}
			}
			
			return result;
		}
		
		private static function layerContainsTypeOfMaterial(typeOfMaterial:Number, layer:Layer):Boolean
		{
			var result:Boolean = false;
			
			for each(var material:Material in layer.materials)
			{
				if(material.type == typeOfMaterial)
				{
					result = true;
				}
			}
			
			return result;
		}
		
		private static function getMaterialByType(typeOfMaterial:Number, layer:Layer):Material
		{
			var result:Material = new Material();
			
			for each(var material:Material in layer.materials)
			{
				if(material.type == typeOfMaterial)
				{
					result = material;
				}
			}
			
			return result;
		}

		private static function constructionIsHomogen(construction:ConstructionLang):Boolean
		{
			var result:Boolean = true;
			
			for each(var layer:Layer in construction.layers)
			{
				if(!layer.homogen)
				{
					result = false;
				}
			}
			
			return result;
		}
		
		private static function maximumNumberOfMaterialsInSingleLayerInConstruction(construction:ConstructionLang):Number
		{
			var result:Number = 0;
			
			for each(var layer:Layer in construction.layers)
			{
				if(result < layer.materials.length)
				{
					result = layer.materials.length;
				}
			}
			
			return result;
		}
		
		private static function layerHasMaterial(typeOfMaterial:Number, layer:Layer):Boolean
		{
			var result:Boolean = false;
			
			for each(var material:Material in layer.materials)
			{
				if(material.type == typeOfMaterial)
				{
					result = true;
				}
			}
			
			return result;
		}	
	}
}